package controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import state.TabState;
import state.TurtleState;
import state.WindowState;
import view.IViewController;
import view.ViewController;
import model.Model;
import model.parser.ParserException;

import java.util.*;

/**
 * The Controller is the controller in the MVC model. It has references to both
 * the model and the view controller. It contains a window state so it knows the
 * state at which the program is in. It also has a currentTabID so that we know
 * which tab is active right now.
 * 
 * @author KevinWang
 * 
 */
public class Controller implements ActionListener,ChangeListener, Observer {
	private Model model;
	private IViewController viewController;
	private int currentTabID;
	// private int currentTurtleID;
	public Map<Integer, TabState> tabMap;
	private int x = 0;
	private int y = 0;
	private WindowState windowstate;

	public Controller(){
		viewController = new ViewController(this, this);
		model = new Model();
		currentTabID=0;
		windowstate = new WindowState();
	}

	/**
	 * actionListener will listen to both the text input and the tab. Depending
	 * on what the source is, different actions will be performed. If it is from
	 * a tab, the currentTabID will be updated. If it is from a text input, the
	 * model will be called to process the string.
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		JTextField source = ((JTextField) e.getSource());
		try{
				
			/*for each user command query, first add controller as the observer to 
			 *the tabstate and all turtlestates in the tabstate, then pass to model 
			 */
			addObservers(windowstate.getTabState(currentTabID));
			viewController.displayText(Integer.toString(model.parse(source.getText(),windowstate.getTabState(currentTabID))));
			windowstate.history.add(source.getText());
			viewController.updateHistory(source.getText());
			source.setText("");
		}catch (ParserException exception)
        {
			//exception.printStackTrace();
			viewController.displayText("Input Error: "+exception.getMessage());
            JOptionPane.showMessageDialog(null,exception.getMessage(),"Input Error",JOptionPane.ERROR_MESSAGE);                         
        }
	}

	@Override
	public void update(Observable o, Object arg) {
		/*
		 * if o is instance of turtle state, do the drawing
		 * if o is instance of tabstate with arg as "clear screen", clear screen
		 * if o is instance of tabstate with arg as integer, add turtle according to the int
		 * 
		 * a smarter implementation for this would be do have the second argument be some kind of executable the viewController could run.
		 * this would be easier to extend
		 */
		if (o instanceof TurtleState) {
			viewController.draw(((TurtleState) o).getOldX(),
					((TurtleState) o).getOldY(), ((TurtleState) o).getX(),
					((TurtleState) o).getY(), ((TurtleState) o).getOrientation(),
					((TurtleState) o).isPenDown(), ((TurtleState) o).getId(), currentTabID);
			// viewController.addTurtle(0, 0);
		} 
		else if (o instanceof TabState && arg instanceof Integer) 
			viewController.addTurtle((Integer) arg, currentTabID);
		else if (o instanceof TabState && arg instanceof String && ((String) arg).equals("ClearScreen")) 
			viewController.clearTab(currentTabID);
		else if (o instanceof TabState && arg instanceof String && ((String) arg).startsWith("VariableUpdate")) {
			String varName = ((String) arg).split(" ")[1];
			viewController.updateVariable(varName);
		}
		else
			throw ParserException.INTERNAL_ERROR;
	}

	public void addObservers(TabState Tabst) {
		Tabst.addObserver(this);
		for (Integer i : Tabst.turtlesMap.keySet()) {
			TurtleState Turst = Tabst.turtlesMap.get(i);
			Turst.addObserver(this);
		}
	}

	@Override
	public void stateChanged(ChangeEvent arg0) {
		JTabbedPane pane = (JTabbedPane)arg0.getSource();
        // Get current tab
        int sel = pane.getSelectedIndex();
        String s = pane.getTitleAt(sel);
        
        //s would return the current title name
        //use split to get the tabID
        if (!s.equals("")){
        	currentTabID = Integer.parseInt(s.split(" ")[1]) - 1;
        	//if not existed, create new tab state
        	windowstate.addTabState(currentTabID);
	        //System.out.println(currentTabID);
        }
        List<String> varList = new ArrayList<String>();
        for (String var : windowstate.tabsMap.get(currentTabID).variables.keySet())
        	varList.add(var);
        viewController.cleanAndUpdate(varList);
        
        //notify the view controller
        viewController.setActiveTab(currentTabID);
	}
	
	public void setActvieTab(int TabID){
		
	}
}
